#pragma once

#include "Socket.hpp"
#include "Reactor.hpp"

using namespace std;
using namespace SocketModule;

// 管理监听套接字，是对Socket模块，Channel模块的⼀个整体封装（组合）
class Acceptor
{
    typedef function<void(int fd)> AcceptCallback;

    // 默认全连接队列大小
    static const uint32_t DefaultBacklog = 256;

private:
    // 创建封装的监听套接字
    SockPtr _listen_socket;
    // 用于事件监控设置
    Reactor *_belongs_reactor;
    // 用于管理监听套接字关心的事件
    Channel _channel;
    // 新连接获取成功之后要调用的回调
    AcceptCallback _accept_callback;

private:
    // 创建监听套接字
    static shared_ptr<TcpSocket> CreateListenSocket(uint16_t port)
    {
        shared_ptr<TcpSocket> tmp = make_shared<TcpSocket>(port);
        tmp->BuildSocket(SockType::LISTEN_SOCK);
        return tmp;
    }
    // 读事件就绪时调用的回调
    void HandleRead()
    {
        LOG(LogLevel::DEBUG) << "监听socket读事件就绪";
        uint32_t ip = 0;
        uint16_t port = 0;
        // 非阻塞循环获取新连接
        while (true)
        {
            int newfd = _listen_socket->Accept(ip, port);
            if (newfd > 0)
            {
                // 调用回调函数为新连接创建Connection对象
                if (_accept_callback)
                {
                    _accept_callback(newfd);
                }
                else
                {
                    LOG(LogLevel::DEADLY) << "获取新连接后，未设置新连接获取成功之后要调用的回调";
                    abort();
                }
            }
            else if (newfd < 0)
            {
                // 连接全部获取完毕
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                // 被信号中断
                else if (errno == EINTR)
                {
                    continue;
                }
                else // listensocketfd异常
                {
                    LOG(LogLevel::DEADLY) << "获取新连接失败，ListenSocket损坏!!!";
                    abort();
                }
            }
        }
    }

public:
    Acceptor(Reactor *belongs_reactor, uint16_t port)
        : _listen_socket(CreateListenSocket(port)),
          _belongs_reactor(belongs_reactor),
          _channel(belongs_reactor, _listen_socket->GetSockfd()),
          _accept_callback(nullptr)
    {
        // 设置默认全连接队列大小
        _listen_socket->SetBacklog(DefaultBacklog);

        // 开启地址端口重用
        SocketModule::ReuseAddress(_listen_socket->GetSockfd());

        // 把监听套接字设置为非阻塞
        SocketModule::FdSetNonBlock(_listen_socket->GetSockfd());

        // 注册监听套接字读事件就绪时调用的回调
        _channel.SetReadCallback([this]()
                                 { this->HandleRead(); });
    }
    // 设置全连接队列大小
    void SetBacklog(uint32_t n)
    {
        _listen_socket->SetBacklog(n);
    }

    // 启动_channel读事件关心
    void Listen()
    {
        _channel.EnableRead();
    }

    void SetAcceptCallback(const AcceptCallback &acc)
    {
        // 设置回调
        _accept_callback = acc;
    }

    // 取消监听
    void CancelListen()
    {
        // 取消监听套接字读事件监控
        _channel.DisableRead();
    }

    ~Acceptor()
    {
        // 移除监听套接字fd事件监控
        _channel.Remove();
        // 关闭监听套接字
        _listen_socket->Close();
    }
};